package gnuplot;

/**
 * 
 * ## gnu plot package.
 * version 0.2
 * 
 * This is the core directly interface to GNUPLOT. All options in graphics 
 * will be implemented here. Note the plotter interface defined in this 
 * same package. Other possible class should be constructed as 
 * implementations of plotter interface.
 * 
 * 
 * This is part of JFEG project, wich is a free project. This is, 
 * therefore, licensed under Eclipse License. Please, visit the
 * following web address so you can read more about this project.
 * 
 * http://code.google.com/p/jfeg/
 * 
 * Feel free to use, study, edit and redistribute under the terms
 * defined in Eclipse license.
 * 
 * - version note -
 *  => data (double[][]) should be implementated with templates, ill handle
 *  		this soon. Next submition, maybe.
 *  => next update ill set this plotter for more than one file.  
 * 
 * @author thiago (twitter: thmosqueiro)
 *
 */

import java.io.*;

public class Gnuplot implements plotter
{
	
/**
 * It would be nice calling isConstructed() method before
 * using other methods (just after instantiation).
 */
	private boolean construction;
/**
 * Data stored in file will be stored in this vector.	
 */
	private double[][] data;
/**
 * Number of the data vector.	
 */
	private int n,m;

	private String gtitle, xlabel, ylabel, terminal, 
					outputname, method; 
	
/**
 * Some optional style option.
 */
	private String optionals = "";
	
/**
 * Data file	
 */
	private FileReader inputfile;
	private String inputfile_name;
	private boolean useDataFile;

	
/**
 * All extra labels.
 */
	private String labels = "";

/**
 * Timing for graphic.
 */
	private double dt = 2;
	private boolean dopause = true;
	
	
	/**
	 * Constructor with incoming data.
	 * 
	 * @param incoming, double[][]
	 * @param n, int
	 * @param m, int 
	 */
	public Gnuplot(double[][] incoming)
	{
		
		n = incoming.length;
		m = incoming[1].length;
		useDataFile = false;
		data = new double[Math.max(m, n)][Math.min(m, n)];
		
		try
		{
			for (int j = 0; j < n; j++)
			{
				for (int k = 0; k < m; k++)
				{
					if (m < n)
						data[j][k] = incoming[j][k];
					else
						data[k][j] = incoming[j][k];
				}
			}

			construction = true;
		}
		catch( ArrayIndexOutOfBoundsException e )
	    {
	      	System.out.print("An expected error has occured.\n");
	       	construction = false;
	       	e.printStackTrace();
	    }
		
	}	
	
	
	/**
	 * Use this constructor if you have an external file
	 * with the data to plot. 
	 * 
	 * @param data_file	:: path and name to file with data.
	 * @param type			:: matrix (m), n columns (nc), 
	 */
	public Gnuplot(String data_file, String type)
	{
	   	inputfile_name = data_file;
	   	useDataFile = true;
	    	
	   	// Construction successfully finished.    	
	    construction = true;
	}
	
	/**
	 * This finally makes the graphic. This method uses a auxiliary 
	 * file, namely auxfile.gp, and gnuplot will run it.
	 */
	public void makeGraphic()
	{
		
		// First, let's create the file 'dot gp'.
		makePlotFile();
		
		if (!useDataFile)
		{	
			makeAuxDataFile();
			inputfile_name = "auxfile.gp";
		}
		
		// Now, we ask GP to run it.
		try
		{
			Runtime.getRuntime().exec("gnuplot auxfile.gp");
			Runtime.getRuntime().exec("rm -f auxfile.gp auxdatafile.jfeg");
		}
		catch ( IOException e ) { /* possible excpetion */  }
		
	}

	
	/**
	 * Creates a 'dot gp' file for gnuplot.
	 */
	private void makePlotFile()
	{
		try
		{
			FileWriter outF = new FileWriter("auxfile.gp");
			PrintWriter out = new PrintWriter(outF);
			
			out.println("set title \"" + gtitle + "\"\n");
			out.println("set xlabel \"" + xlabel + "\"\n");
			out.println("set ylabel \"" + ylabel + "\"\n");
			out.println(optionals);
			
			out.println(terminal);
			if (dopause) { out.println("set pause " + dt + "\n"); }
			out.println(method + " \"" + inputfile_name + "\"");
			
			// It's done, closing document.
			out.close();
		}
		catch( IOException e )
        {
        	System.out.print("An expected error has occured.\n");
        	construction = false;
        	e.printStackTrace();
        }
	}
	
	/**
	 * Creates a data file prepared to gnuplot.
	 */
	private void makeAuxDataFile()
	{
		String dtfile;
		
		try
		{
			
			FileWriter outF = new FileWriter("auxdatafile.jfeg");
			PrintWriter out = new PrintWriter(outF);
			
			dtfile = "";

			try
			{
				for (int j = 0; j < n; j++)
				{
					for (int k = 0; k < m; k++)
					{
						dtfile += data[j][k] + " " + data[j][k] + "\n";
					}
				}
			}
			catch( ArrayIndexOutOfBoundsException e )
	        {
	        	System.out.print("An expected error has occured.\n");
	        	construction = false;
	        	e.printStackTrace();
	        }

			out.print(dtfile);
			out.close();
		}
		catch( IOException e )
        {
        	System.out.print("An expected error has occured.\n");
        	construction = false;
        	e.printStackTrace();
        }

	}
	
	/**
	 * Set up the outputs, i.e., sets the terminal (gif, jpeg, 
	 * ps, pstricks, etc) and the file name for this output. Since 
	 * terminal is not default anymore, there won't be any delay. 
	 * For a brute force delay setting, use setDelay method AFTER
	 *  calling setOutputs.
	 * 
	 * @param filename, string
	 * @param type, string
	 */
	public void setOutput(String filename, String type)
	{
		outputname = filename;
		dopause = false;
		terminal = "set term " + type + "\n" +
			"set output \"" + filename + "\"";
	}

	/**
	 * 
	 * This method sets up the plot method. For plotting 3D
	 * surfaces or special kinds of data, use this method to 
	 * specify it. By default, plot method is set to "plot"
	 * 
	 * @param plotmethod, String
	 */
	public void setPlotMethod(String plotmethod) { method = plotmethod; }
	
	/**
	 * Sets the graphic title.
	 *  
	 * @param title, string
	 */
	public void setTitle(String title)	{ gtitle = title; }
	
	/**
	 * Sets X axes label.
	 *  
	 * @param lab, string
	 */
	public void setXLabel(String lab)	{ xlabel = lab; }

	/**
	 * Sets Y axes label.
	 *  
	 * @param lab, string
	 */
	public void setYLabel(String lab)	{ ylabel = lab; }	
	
	/**
	 * Sets the point size.
	 *  
	 * @param x, double
	 */
	public void setPointSize(double x)	
	{
		optionals += "set pointsize " + x + "\n;";
	}

	/**
	 * Sets the point size.
	 *  
	 * @param x, double
	 */
	public void setLabel(String text, double x, double y)	
	{
		labels += "set label \"" + text + "\" at graph " + x 
				+ ", graph " + y + "\n;";
	}
	

	/**
	 * After running gnu plot, the graphic will be prompted in screen,
	 * and then it closes automatically. Setting a delay may help
	 * when creating graphic. By default, this time is set to 3 seconds.
	 * 
	 * If terminal is not the default one, please set this delay again. 
	 *  
	 * @param dt, double
	 */
	public void setDelay(double tempo)	
	{ 
		dopause = true;
		dt = tempo; 
	}	
	
	/**
	 * Verifies if the constructor method could complete
	 * its tasks.
	 * 
	 * @return boolean, true if construction was performed.
	 */
	public boolean isConstructed() { return(construction); }

	public int numPoints() { return(n); }
}